package com.audaque.springboot.foshanupload.core.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.Months;
import org.joda.time.format.DateTimeFormat;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Objects;

/**
 * @author zgb
 * @desc ...
 * @date 2023-03-01 19:17:00
 */
@Slf4j
public class DateUtilsExtJoda {

    public static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private static ZoneId ZONE = ZoneId.systemDefault();

    public static String nowYear() {
        return DateTime.now().toString("yyyy");
    }

    public static String nowMonth() {
        return DateTime.now().toString("yyyyMM");
    }

    public static String nowDate() {
        return DateTime.now().toString("yyyyMMdd");
    }

    public static String lastNMonth(int n) {
        return DateTime.now().plusMonths(n).toString("yyyyMM");
    }

    public static boolean currentMonth(Date date) {
        return nowMonth().equals(new DateTime(date).toString("yyyyMM"));
    }

    public static LocalDateTime parse(String dateValue) {
        if (StringUtils.isEmpty(dateValue)) {
            return null;
        }
        try {
            return LocalDateTime.parse(dateValue, DATETIME_FORMATTER);
        } catch (DateTimeParseException e) {
            log.warn("parse failed. dateValue={}, format={}", dateValue, DATETIME_FORMATTER, e);
        }
        return null;
    }

    /**
     *  下月第一天零点 00:00:00
     * @param n
     * @return
     */
    public static long nextNMonthWithMinimumValueWithMillis(int n) {
        return DateTime.now().plusMonths(n).dayOfMonth().withMinimumValue().withMillisOfDay(0).getMillis();
    }

    public static Date nextNMonthWithMinimumValueWithDate(int n) {
        return DateTime.now().plusMonths(n).dayOfMonth().withMinimumValue().withMillisOfDay(0).toDate();
    }

    public static long nextNMonthWithMinimumValueWithMillis(long startTime, int n) {
        return new DateTime(startTime).plusMonths(n).dayOfMonth().withMinimumValue().withMillisOfDay(0).getMillis();
    }

    public static boolean isNotInPerMonthLastSixHour(long nowMillis) {
        return nowMillis < DateTime.now().plusMonths(1).dayOfMonth().withMinimumValue().withMillisOfDay(0).plusHours(-6).getMillis();
    }

    public static boolean isNotInPerMonthLastFourDay(long nowMillis) {
        return nowMillis < DateTime.now().plusMonths(1).dayOfMonth().withMinimumValue().withMillisOfDay(0).plusDays(-4).getMillis();
    }

    public static String lastDate() {
        return DateTime.now().dayOfMonth().withMaximumValue().toString("yyyyMMdd");
    }

    public static String firstDate() {
        return DateTime.now().dayOfMonth().withMinimumValue().toString("yyyyMMdd");
    }

    public static String firstTwoDate() {
        return DateTime.now().dayOfMonth().withMinimumValue().plusDays(1).toString("yyyyMMdd");
    }

    /**
     * 下个月N号
     * @param nx
     * @return
     */
    public static Date nextMonthNXDate(Integer nx) {
        return DateTime.now().plusMonths(1).dayOfMonth().withMinimumValue().plusDays(nx-1).toDate();
    }

    /**
     *  N个月后最后一天
     * @param nx
     * @return
     */
    public static DateTime nextNXMonthLastDate(Integer nx) {
        return DateTime.now().plusMonths(nx).dayOfMonth().withMaximumValue();
    }


    /**
     *  相差月份
     * @param start
     * @param end
     * @return
     */
    public static Integer differMonthsTwoDate(DateTime start,DateTime end) {
        return Months.monthsBetween(start, end).getMonths();
    }


    /**
     *  相差天数
     * @param start
     * @param end
     * @return
     */
    public static Integer differDaysTwoDate(DateTime start, DateTime end) {
        return Days.daysBetween(start, end).getDays();
    }


    /**
     *  过期
     * @param date
     * @return
     */
    public static Boolean isExpired(Date date) {
        return DateTime.now().isAfter(new DateTime(date))|| Objects.equals(DateTime.now().toString("yyyyMM"),new DateTime(date).toString("yyyyMM"));
    }

    /**
     *  月末最后一天
     * @return
     */
    public static Boolean isMonthLastDay(){
        return 0 == differDaysTwoDate(DateTime.now(), DateTime.now().dayOfMonth().withMaximumValue());
    }

    public static String getBeforeAfterDate(String datestr, int day) {
        return DateTime.parse(datestr, DateTimeFormat.forPattern("yyyy-MM-dd")).plusDays(day).toString("yyyy-MM-dd");
    }

    /**
     *  between
     * @param start
     * @param end
     * @param datetime
     * @return
     */
    public static Boolean between(String start, String end,String datetime) {
        return datetime.compareTo(start) >= 0 && datetime.compareTo(end) <= 0;
    }

    /**
     * 判断时间是否在两个整点之间
     *
     * @param start 0-23
     * @param end   1-23
     * @param time
     * @return
     */
    public static Boolean betweenHour(Integer start, Integer end, LocalTime time) {
        if (start == null || end == null || start > end) {
            return false;
        }
        return time.isAfter(LocalTime.of(start, 0, 0)) && time.isBefore(LocalTime.of(end, 0, 0));
    }

    public static LocalDateTime getLocalDateTimeBySeconds(Long seconds){
        return LocalDateTime.ofInstant(Instant.ofEpochSecond(seconds), ZONE);
    }

    public static String formatToStr(LocalDateTime t) {
        return t.format(DATETIME_FORMATTER);
    }

    public static String formatToStr(Long seconds) {
        return getLocalDateTimeBySeconds(seconds).format(DATETIME_FORMATTER);
    }

    /**
     * 计算当天到第二天的凌晨的时间秒数
     * @return
     */
    public static int getTomorrowSeconds(){
        Date currentTime = new Date();
        //从一个 Instant和区域ID获得 LocalDateTime实例
        LocalDateTime localDateTime = LocalDateTime.ofInstant(currentTime.toInstant(), ZoneId.systemDefault());
        //获取第第二天零点时刻的实例
        LocalDateTime toromorrowTime = LocalDateTime.ofInstant(currentTime.toInstant(), ZoneId.systemDefault())
                .plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
        //ChronoUnit日期枚举类,between方法计算两个时间对象之间的时间量
        long seconds = ChronoUnit.SECONDS.between(localDateTime, toromorrowTime);
        return (int)seconds;
    }

    /**
     * 获取当前日期(yyyy-MM-dd)
     *
     * @return Date
     */
    public static Date getNowDate() {
        return new DateTime().toDate();
    }

    /**
     * 获取当前日期(yyyy-MM-dd)
     *
     * @return Date
     */
    public static String getNowDateToString() {
        return new DateTime().toString(DateFormatUtil.DATE_DEFAULT_FORMAT);
    }


    /**
     * 获取当前日期(yyyy-MM-dd)
     *
     * @return
     */
    public static String getNowDateTimeToString() {
        return new DateTime().toString(DateFormatUtil.DATE_DEFAULT_FORMAT);
    }

    /**
     * 日期格式化yyyy-MM-dd
     *
     * @param date
     * @return DATE
     */
    public static Date getDate(Date date) {
        try {
            return new DateTime(getDateToString(date)).toDate();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }




    /**
     * 日期格式化yyyy-MM-dd
     *
     * @param date
     * @return String
     */
    public static String getDateToString(Date date) {
        return new DateTime(date).toString(DateFormatUtil.DATE_DEFAULT_FORMAT);
    }

    /**
     * 日期格式化yyyy-MM-dd
     *
     * @param date
     * @return String
     */
    public static String getDateToStringEx(Date date) {
        if (null == date) {
            return "";
        }
        return new DateTime(date).toString(DateFormatUtil.DATE_DEFAULT_FORMAT);
    }

    public static String getDateToStringhour(Date date) {
        if (null == date) {
            return "";
        }
        return new DateTime(date).toString(DateFormatUtil.TIME_DEFAULT_FORMAT);
    }

    /**
     * 日期格式化yyyy-MM-dd hh:MM:ss
     *
     * @param date
     * @return String
     */
    public static String getDateToStrings(Date date) {
        return new DateTime(date).toString(DateFormatUtil.DATETIME_DEFAULT_FORMAT);
    }



    /**
     * 日期格式化
     *
     * @param date
     * @param formatStr
     * @return
     */
    public static String getDateFormatToString(Date date, String formatStr) {
        if (org.apache.commons.lang3.StringUtils.isNotBlank(formatStr)) {
            return new DateTime(date).toString(formatStr);
        }
        return null;
    }

    /**
     * 日期格式化
     *
     * @param date
     * @param formatStr
     * @return
     */
    public static Date getDateFormat(Date date, String formatStr) {
        if (org.apache.commons.lang3.StringUtils.isNotBlank(formatStr)) {
            return new DateTime(new DateTime(date).toString(formatStr)).toDate();
        }
        return null;
    }



    /**
     * 日期格式化 yyyy-MM-dd HH:mm:ss
     *
     * @param date
     * @return DATE
     */
    public static Date getDateTime(Date date) {
        try {
            return new DateTime(date).toDate();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 日期格式化 yyyy-MM-dd HH:mm:ss
     *
     * @param date
     * @return String
     */
    public static String getDateTimeToString(Date date) {
        return new DateTime(date).toString(DateFormatUtil.DATETIME_DEFAULT_FORMAT);
    }


    /**
     * 获取指定日期年份
     *
     * @param date
     * @return
     */
    public static int geYear(Date date) {
        return new DateTime(date).getYear();
    }


    /**
     * 获取指定日期年份
     *
     * @param date
     * @return
     */
    public static int getYear(Date date) {
        return new DateTime(date).getYear();
    }

    /**
     * 获取指定日期月份
     *
     * @param date
     * @return
     */
    public static int getMonth(Date date) {
        return new DateTime(date).getMonthOfYear();
    }



    /**
     * 获取指定日期天数（号）
     *
     * @param date
     * @return
     */
    public static int getDay(Date date) {
        return new DateTime(date).getDayOfMonth();
    }







    /**
     * 增加日期的年份。失败返回null。
     *
     * @param date       日期
     * @param yearAmount 增加数量。可为负数
     * @return 增加年份后的日期
     */
    public static Date addYear(Date date, int yearAmount) {
        return new DateTime(date).plusMonths(yearAmount).toDate();
    }

    /**
     * 增加日期的月份。失败返回null。
     *
     * @param date        日期
     * @param monthAmount 增加数量。可为负数
     * @return 增加月份后的日期
     */
    public static Date addMonth(Date date, int monthAmount) {
        return new DateTime(date).plusMonths(monthAmount).toDate();
    }



    /**
     * 增加日期的天数。失败返回null。
     *
     * @param date      日期
     * @param dayAmount 增加数量。可为负数
     * @return 增加天数后的日期
     */
    public static Date addDay(Date date, int dayAmount) {
        return new DateTime(date).plusDays(dayAmount).toDate();
    }

    /**
     * 设置指定日期（天）。失败返回null。
     *
     * @param date      日期
     * @param dayAmount 增加数量。可为负数
     * @return 增加天数后的日期
     */
    public static Date setDay(Date date, int dayAmount) {
        DateTime dateTime = new DateTime(date);
        return new DateTime(dateTime.getYear(), dateTime.getMonthOfYear(), dayAmount, dateTime.getHourOfDay(), dateTime.getMillisOfDay()).toDate();
    }





}
